﻿namespace ECM7.Themes.Editor
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Windows.Forms;

	using ECM7.Themes.Domain.Model;
	using ECM7.Themes.Domain.Model.Base;
	using ECM7.Themes.Domain.Model.Styles;
	using ECM7.Themes.Domain.Model.Templates;
	using ECM7.Themes.Domain.Services;

	/// <summary>
	/// Форма редактирования параметров темы оформления
	/// </summary>
	public partial class ThemeEditorForm : Form
	{
		#region Свойства формы

		/// <summary>
		/// Список параметров стилей
		/// </summary>
		private readonly ThemeConfiguration config;

		/// <summary>
		/// Значения свойств темы оформления
		/// </summary>
		private readonly UserData userData;

		#region Шорткаты

		/// <summary>
		/// Выбранный пользователем шаблон страницы
		/// </summary>
		private Template Template
		{
			get { return config.Templates[userData.TemplateGuid]; }
		}

		/// <summary>
		/// Основной файл состилями
		/// </summary>
		private Style Style
		{
			get { return config.Style; }
		}

		/// <summary>
		/// Настройки приложения
		/// </summary>
		private readonly ApplicationSettings applicationSettings;

		#endregion

		#endregion

		#region Инициализация

		/// <summary>
		/// Инициализация формы
		/// </summary>
		/// <param name="configuration">Конфигурация</param>
		/// <param name="data">Данные,введённые пользователем в предыдущий раз</param>
		/// <param name="appSettings">Настройки приложения</param>
		public ThemeEditorForm(ThemeConfiguration configuration, UserData data, ApplicationSettings appSettings)
		{
			InitializeComponent();

			config = configuration;
			userData = data;
			applicationSettings = appSettings;
		}

		/// <summary>
		/// Инициализация
		/// </summary>
		/// <param name="configuration">Конфигурация</param>
		/// <param name="templateGuid">GUID выбранного шаблона</param>
		/// <param name="appSettings">Настройки приложения</param>
		public ThemeEditorForm(ThemeConfiguration configuration, Guid templateGuid, ApplicationSettings appSettings)
		{
			InitializeComponent();

			config = configuration;
			userData = new UserData { TemplateGuid = templateGuid };
			applicationSettings = appSettings;

			// значения по умолчанию
			SetDefaultValuesRecursive(Style);
			SetDefaultValues(Template.Parameters);
		}

		/// <summary>
		/// Установить значения по умолчанию для подстилей
		/// </summary>
		private void SetDefaultValuesRecursive(Style style)
		{
			SetDefaultValues(style.Parameters);

			if (style.ChildStyles != null)
			{
				foreach (var item in style.ChildStyles)
				{
					SetDefaultValuesRecursive(item);
				}
			}
		}

		/// <summary>
		/// Установка значений по умолчанию
		/// </summary>
		/// <typeparam name="TValue">Тип значения</typeparam>
		/// <param name="parameters">Список параметров</param>
		private void SetDefaultValues<TValue>(Dictionary<Guid, TValue> parameters)
			where TValue : ThemeParameter
		{
			foreach (var p in parameters)
			{
				userData.Values[p.Key] = p.Value.DefaultValue;
			}
		}

		#endregion

		#region Редактирование данных пользователем

		/// <summary>
		/// Действия при открытии формы
		/// </summary>
		private void ThemeEditorFormLoad(object sender, EventArgs e)
		{
			WindowState = FormWindowState.Maximized;

			// todo: вынести константы в ресурсы
			// todo: разделить название шаблона и название узла дерева по разным свойствам
			TreeNode rootNode = InitTreenNode(tvTemplateAndStyle.Nodes, Template);
			CreateNodes(Template.Parameters, rootNode);
			rootNode = InitTreenNode(tvTemplateAndStyle.Nodes, Style);
			CreateSubtreeStyles(Style, rootNode);
		}

		/// <summary>
		/// Создать дерево подстилей
		/// </summary>
		private static void CreateSubtreeStyles(Style style, TreeNode rootNode)
		{
			CreateNodes(style.Parameters, rootNode);

			if (style.ChildStyles != null)
			{
				foreach (Style substyle in style.ChildStyles)
				{
					TreeNode rootSubNode = InitTreenNode(rootNode.Nodes, substyle);
					CreateSubtreeStyles(substyle, rootSubNode);
				}
			}
		}

		/// <summary>
		/// Добавление элемента в дерево
		/// </summary>
		/// <param name="nodeCollection">Коллекция элементов</param>
		/// <param name="obj">Объект, на основе которого создается элемент дерева</param>
		/// <returns>Возвращает созданный элемент</returns>
		private static TreeNode InitTreenNode(TreeNodeCollection nodeCollection, GuiElement obj)
		{
			TreeNode newNode = nodeCollection.Add(obj.Name);
			newNode.SelectedImageIndex = newNode.ImageIndex = obj.ImageIndex;

			return newNode;
		}

		/// <summary>
		/// Добавить группу узлов с корнем на верхнем уровне дерева
		/// </summary>
		/// <typeparam name="TValue">Тип параметра</typeparam>
		/// <param name="parameters">Параметры (2 уровень)</param>
		/// <param name="rootNode">Корневой узел</param>
		private static void CreateNodes<TValue>(Dictionary<Guid, TValue> parameters, TreeNode rootNode)
			where TValue : ThemeParameter
		{
			// создаем дочерние узлы для параметров
			foreach (var item in parameters)
			{
				TreeNode newNode = InitTreenNode(rootNode.Nodes, item.Value);
				newNode.Tag = new TreeNodeObject
				{
					ObjGuid = item.Key,
					EditObject = item.Value,
				};
			}
		}

		/// <summary>
		/// Событие срабатывает после выбора элемента дерева
		/// </summary>
		private void TvTemplateAndStyleAfterSelect(object sender, TreeViewEventArgs e)
		{
			// если узел связан с данными, то отображаем их в поле редактирования
			if (e.Node != null)
			{
				TreeNodeObject treeObject = e.Node.Tag as TreeNodeObject;
				tbUserData.Enabled = treeObject != null;
				tbUserData.Text = treeObject == null ? string.Empty : userData.Values[treeObject.ObjGuid];
			}
		}

		/// <summary>
		/// Событие редактирования текстового поля
		/// </summary>
		private void TbUserDataTextChanged(object sender, EventArgs e)
		{
			if (tvTemplateAndStyle.SelectedNode != null)
			{
				TreeNodeObject treeObject = tvTemplateAndStyle.SelectedNode.Tag as TreeNodeObject;

				if (treeObject != null)
				{
					userData.Values[treeObject.ObjGuid] = tbUserData.Text;
				}
			}
		}

		#endregion

		#region Пункты главного меню

		/// <summary>
		/// Сгенерировать файлы темы оформления
		/// </summary>
		private void MiBuildClick(object sender, EventArgs e)
		{
			using (var chooseFolder = new FolderBrowserDialog())
			{
				if (chooseFolder.ShowDialog(MdiParent) == DialogResult.OK)
				{
					if (Directory.Exists(chooseFolder.SelectedPath))
					{
						ThemeBuilder builder = new ThemeBuilder();
						builder.Build(chooseFolder.SelectedPath, config, userData, false);

						// todo: вынести строки в ресурсы
						MessageBox.Show("Данные успешно сохранены");
					}
					else
					{
						throw new Exception("Выбранная папка не существует");
					}
				}
			}
		}

		/// <summary>
		/// Сохранить в файл введённые пользователем данные
		/// </summary>
		private void TsmiSaveClick(object sender, EventArgs e)
		{
			SaveFileDialog dialog = new SaveFileDialog();

			if (dialog.ShowDialog() == DialogResult.OK)
			{
				JsonHelper.SaveToFile(dialog.FileName, userData);
			}
		}

		#endregion

		/// <summary>
		/// Открыть форму предварительного просмотра
		/// </summary>
		private void TsmiPreviewClick(object sender, EventArgs e)
		{
			ThemeBuilder builder = new ThemeBuilder();
			builder.Build(applicationSettings.TemplatesPath, config, userData, true);
			Preview formPreview = new Preview(applicationSettings.TemplatesPath + "\\" + Template.Name + ".html");
			formPreview.ShowDialog();
		}
	}
}
